import { PropsWithChildren, ReactNode, useRef, useState } from "react";
import clsm from "@/lib/utils/clsm";
import useLatestRef from "@/lib/hooks/useLatestRef";
import DownIcon from "@/assets/icons/down.svg?jsx";
import useUpdated from "@/lib/hooks/useUpdated";

type CollapseProps = PropsWithChildren<{
  title: ReactNode;
  className?: string;
  unmountOnHide?: boolean;
}>;
export default function Collapse(props: CollapseProps) {
  const { title, children, className, unmountOnHide = true } = props;
  const containerRef = useRef<HTMLDivElement>(null);
  const [open, setOpen] = useState(false);
  const [height, setHeight] = useState<number | "auto">(0);
  const [mount, setMount] = useState(open);
  const transitionRef = useRef({
    isPending: false,
    callback: null as
      | ((this: HTMLDivElement, e: TransitionEvent) => void)
      | null,
  });

  // const mountRef = useLatestRef(mount);
  const unmountOnHideRef = useLatestRef(unmountOnHide);
  useUpdated(() => {
    const el = containerRef.current;
    if (el && transitionRef.current.isPending) {
      el.removeEventListener("transitionend", transitionRef.current.callback!);
      transitionRef.current = {
        isPending: false,
        callback: null,
      };
    }

    if (open) {
      transitionRef.current = {
        isPending: true,
        callback: function (e) {
          if (e.propertyName === "height") {
            setHeight("auto");
            transitionRef.current = {
              isPending: false,
              callback: null,
            };
          }
        },
      };
      if (el) {
        setHeight(el.scrollHeight);
      } else {
        setMount(true);
        requestAnimationFrame(() => {
          // el may be undefined, use ref instead
          setHeight(containerRef.current!.scrollHeight);
        });
      }
    } else if (el) {
      if (transitionRef.current.isPending) {
        setHeight(0);
      } else {
        setHeight(el.scrollHeight);
        requestAnimationFrame(() => {
          setHeight(0);
        });
      }
      transitionRef.current = {
        isPending: true,
        callback: function (e) {
          if (e.propertyName === "height") {
            unmountOnHideRef.current && setMount(false);
            transitionRef.current = {
              isPending: false,
              callback: null,
            };
          }
        },
      };
    }

    if (el && transitionRef.current.callback) {
      el.addEventListener("transitionend", transitionRef.current.callback, {
        once: true,
      });
    }
  }, [open]);

  return (
    <div className={className}>
      <div
        className="flex cursor-pointer items-center gap-x-1"
        onClick={() => setOpen(!open)}
      >
        <span>{title}</span>
        <DownIcon
          height="1em"
          width="1em"
          className={clsm(
            "transition-transform duration-200",
            open && "rotate-180",
          )}
        />
      </div>
      {mount && (
        <div
          ref={containerRef}
          className="overflow-hidden transition-[height] duration-300"
          style={{ height }}
        >
          {children}
        </div>
      )}
    </div>
  );
}
